package cn.onecloud.examples.database;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.keijack.database.hibernate.HqlAndParams;
import com.keijack.database.hibernate.HqlGenerator;

/**
 * 
 * @author keijack.wu
 *
 */
@Repository
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public class CommonHqlDao {

    private final Logger logger = Logger.getLogger(getClass());

    @Autowired
    private SessionFactory sessionFactory;

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void delete(Object obj) {
	if (obj == null) {
	    return;
	}
	this.sessionFactory.getCurrentSession().delete(obj);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void delete(Class<?> clazz, Serializable id) {
	if (id == null) {
	    return;
	}
	this.delete(this.get(clazz, id));
    }

    @SuppressWarnings("unchecked")
    public <T> T get(Class<T> clazz, Serializable id) {
	if (id == null) {
	    return null;
	}
	return (T) this.sessionFactory.getCurrentSession().get(clazz, id);
    }

    @SuppressWarnings("unchecked")

    public <T> T get(Class<T> clazz, String hql, Object[] params) {
	Query query = this.createQuery(hql, params);
	return (T) query.uniqueResult();
    }

    public <T> List<T> query(Class<T> clazz, Object queryParams) {
	HqlAndParams hqlAndParams = HqlGenerator.generateHql(queryParams);
	logger.debug("hqlString=" + hqlAndParams.getHql());
	return this.query(clazz, hqlAndParams.getHql(),
		hqlAndParams.getParams());
    }

    public <T> List<T> query(Class<T> clazz, String hql, Object[] params) {
	Query query = createQuery(hql, params);
	@SuppressWarnings("unchecked")
	List<T> resultList = query.list();
	return resultList;
    }

    private Query createQuery(String hql, Object[] params) {
	Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
	if (params != null && params.length > 0) {
	    for (int i = 0; i < params.length; i++) {
		query.setParameter(i, params[i]);
	    }
	}
	return query;
    }

    public <T> List<T> query(Class<T> clazz, Object queryParams, int page,
	    int rowsPerPage) {
	HqlAndParams hqlAndParams = HqlGenerator.generateHql(queryParams);
	return this.query(clazz, hqlAndParams.getHql(),
		hqlAndParams.getParams(), page, rowsPerPage);
    }

    public <T> List<T> query(Class<T> clazz, String hql, Object[] params,
	    int page, int rowsPerPage) {
	Query query = createQuery(hql, params);
	int firstResult = rowsPerPage * (page - 1);
	query.setFirstResult(firstResult);
	query.setMaxResults(rowsPerPage);
	@SuppressWarnings("unchecked")
	List<T> resultList = query.list();
	return resultList;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void save(Object object) {
	this.sessionFactory.getCurrentSession().save(object);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void saveOrUpdate(Object object) {
	this.sessionFactory.getCurrentSession().saveOrUpdate(object);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void saveOrUpdateAll(Collection<?> collection) {
	for (Object item : collection) {
	    this.saveOrUpdate(item);
	}
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void update(Object object) {
	this.sessionFactory.getCurrentSession().update(object);
    }

    public Number querySize(Object params) {
	HqlAndParams hqlAndParams = HqlGenerator.generateHql(params);
	String countHql = "select count(*) " + hqlAndParams.getHql();
	return this.get(Number.class, countHql, hqlAndParams.getParams());
    }

    public Number querySizeByIdColumn(Object params) {
	HqlAndParams hqlAndParams = HqlGenerator.generateHql(params);
	String countHql = "select count(id) " + hqlAndParams.getHql();
	return this.get(Number.class, countHql, hqlAndParams.getParams());
    }

}
